import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { promises as fs } from 'fs';
import * as fsSync from 'fs';
import * as path from 'path';

/**
 * 加载器工具类
 * 基于 NestJS 实现 Java 风格的 JsonModuleLoader
 * 对应 Java: JsonModuleLoader
 */
@Injectable()
export class LoaderUtils {
  private readonly logger = new Logger(LoaderUtils.name);
  private readonly moduleCache = new Map<string, any>();

  constructor(private readonly configService: ConfigService) {}

  /**
   * 加载 JSON 模块
   * @param moduleName 模块名称
   * @param filePath 文件路径
   * @returns 模块内容
   */
  async loadJsonModule(moduleName: string, filePath: string): Promise<any> {
    try {
      const fullPath = path.resolve(filePath);

      try {
        await fs.access(fullPath);
      } catch (error) {
        this.logger.warn(`文件不存在: ${fullPath}`);
        return null;
      }

      const content = JSON.parse(await fs.readFile(fullPath, 'utf8'));
      this.moduleCache.set(moduleName, content);

      this.logger.log(`加载 JSON 模块成功: ${moduleName}`);
      return content;
    } catch (error) {
      this.logger.error(`加载 JSON 模块失败: ${moduleName}`, error);
      return null;
    }
  }

  /**
   * 加载多个 JSON 模块并合并为数组
   * @param moduleName 模块名称
   * @param filePaths 文件路径数组
   * @returns 合并后的数组
   */
  async mergeContentToArray(
    moduleName: string,
    filePaths: string[],
  ): Promise<any[]> {
    try {
      const results: any[] = [];

      for (const filePath of filePaths) {
        const content = await this.loadJsonModule(
          `${moduleName}_${path.basename(filePath)}`,
          filePath,
        );
        if (content) {
          if (Array.isArray(content)) {
            results.push(...content);
          } else {
            results.push(content);
          }
        }
      }

      this.logger.log(
        `合并内容到数组成功: ${moduleName}, 共 ${results.length} 项`,
      );
      return results;
    } catch (error) {
      this.logger.error(`合并内容到数组失败: ${moduleName}`, error);
      return [];
    }
  }

  /**
   * 加载多个 JSON 模块并合并为对象
   * @param moduleName 模块名称
   * @param filePaths 文件路径数组
   * @returns 合并后的对象
   */
  async mergeContentToObject(
    moduleName: string,
    filePaths: string[],
  ): Promise<Record<string, any>> {
    try {
      const result: Record<string, any> = {};

      for (const filePath of filePaths) {
        const content = await this.loadJsonModule(
          `${moduleName}_${path.basename(filePath)}`,
          filePath,
        );
        if (content && typeof content === 'object') {
          Object.assign(result, content);
        }
      }

      this.logger.log(`合并内容到对象成功: ${moduleName}`);
      return result;
    } catch (error) {
      this.logger.error(`合并内容到对象失败: ${moduleName}`, error);
      return {};
    }
  }

  /**
   * 从目录加载所有 JSON 文件
   * @param moduleName 模块名称
   * @param dirPath 目录路径
   * @returns 加载的内容
   */
  async loadFromDirectory(moduleName: string, dirPath: string): Promise<any[]> {
    try {
      const fullPath = path.resolve(dirPath);

      try {
        await fs.access(fullPath);
      } catch (error) {
        this.logger.warn(`目录不存在: ${fullPath}`);
        return [];
      }

      const files = await fs.readdir(fullPath);
      const jsonFiles = files.filter((file) => file.endsWith('.json'));
      const filePaths = jsonFiles.map((file) => path.join(fullPath, file));

      return await this.mergeContentToArray(moduleName, filePaths);
    } catch (error) {
      this.logger.error(`从目录加载失败: ${moduleName}`, error);
      return [];
    }
  }

  /**
   * 获取缓存的模块
   * @param moduleName 模块名称
   * @returns 缓存的模块内容
   */
  getCachedModule(moduleName: string): any {
    return this.moduleCache.get(moduleName);
  }

  /**
   * 清除模块缓存
   * @param moduleName 模块名称，不传则清除所有
   */
  clearCache(moduleName?: string): void {
    if (moduleName) {
      this.moduleCache.delete(moduleName);
      this.logger.log(`清除模块缓存: ${moduleName}`);
    } else {
      this.moduleCache.clear();
      this.logger.log('清除所有模块缓存');
    }
  }

  /**
   * 重新加载模块
   * @param moduleName 模块名称
   * @param filePath 文件路径
   * @returns 重新加载的内容
   */
  async reloadModule(moduleName: string, filePath: string): Promise<any> {
    this.clearCache(moduleName);
    return await this.loadJsonModule(moduleName, filePath);
  }

  /**
   * 监听文件变化并自动重新加载
   * @param moduleName 模块名称
   * @param filePath 文件路径
   * @param callback 变化回调
   */
  watchModule(
    moduleName: string,
    filePath: string,
    callback: (content: any) => void,
  ): void {
    const fullPath = path.resolve(filePath);

    // 使用 fs.watch 替代 fs.watchFile
    const watcher = fsSync.watch(fullPath, (eventType) => {
      if (eventType === 'change') {
        this.logger.log(`文件变化，重新加载: ${moduleName}`);
        this.reloadModule(moduleName, filePath).then((content) => {
          callback(content);
        });
      }
    });

    this.logger.log(`开始监听文件变化: ${moduleName}`);
  }

  /**
   * 停止监听文件变化
   * @param filePath 文件路径
   */
  unwatchModule(filePath: string): void {
    const fullPath = path.resolve(filePath);
    // fs.watch 返回的 watcher 需要手动关闭
    // 这里需要维护一个 watcher 映射来管理
    this.logger.log(`停止监听文件变化: ${filePath}`);
  }

  /**
   * 获取所有缓存的模块名称
   * @returns 模块名称数组
   */
  getCachedModuleNames(): string[] {
    return Array.from(this.moduleCache.keys());
  }

  /**
   * 获取缓存统计信息
   * @returns 缓存统计信息
   */
  getCacheStats(): {
    moduleCount: number;
    moduleNames: string[];
    totalSize: number;
  } {
    const moduleNames = this.getCachedModuleNames();
    let totalSize = 0;

    for (const [name, content] of this.moduleCache) {
      totalSize += JSON.stringify(content).length;
    }

    return {
      moduleCount: this.moduleCache.size,
      moduleNames,
      totalSize,
    };
  }
}
